package com.wider.services.impl;

import com.wider.pojo.BaseData;
import com.wider.pojo.MinAndMax;
import com.wider.pojo.WideData;
import com.wider.services.BaseDataService;
import com.wider.services.DataService;
import com.wider.services.FlowServices;
import com.wider.services.WideDataService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.sql.DataSource;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.Statement;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class FlowStreamServicesImpl implements FlowServices {

    @Autowired
    DataService dataService;

    @Autowired
    WideDataService wideDataService;

    @Autowired
    DataSource dataSource;

    private List<Integer> historytimeDifference = Arrays.asList(-240, -120, -60, -30, -20, -15, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1);
    private List<Integer> futuretimeDifference = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 30, 60, 120, 240);

    @Override
    public void processingData(String caseName) {

    }

    @Override
    public boolean processingData(LocalDateTime processTime, String caseName) {
        return false;
    }

    @Override
    public void processingData(List<BaseData> baseDataList, LocalDateTime processTime, String caseName) {
        WideData wideData = new WideData();
        HashMap<LocalDateTime, List<BigDecimal>> collect = baseDataList.stream()
                .collect(Collectors.groupingBy(
                        // 转换key，将日期时间舍弃秒信息
                        baseData -> baseData.getDate().truncatedTo(ChronoUnit.MINUTES),
                        // 初始化映射值列表
                        HashMap::new,
                        // 收集器，将每项数据的BigDecimal添加到对应的分钟桶里
                        Collectors.mapping(BaseData::getData, Collectors.toList())
                ));
        processTime = processTime.truncatedTo(ChronoUnit.MINUTES);
        List<BigDecimal> valueList = collect.get(processTime);
        BigDecimal median = dataService.findMedian(valueList);
        MinAndMax minAndMax = dataService.getMinAndMax( valueList);
        wideData.setMaxData(minAndMax.getMaxValue());
        wideData.setMinData(minAndMax.getMinValue());
        wideData.setNowData(median);
        wideData.setDateTime(processTime);
        List<Integer> alltimeDifference = new ArrayList<>(historytimeDifference);
        alltimeDifference.addAll(futuretimeDifference);
        for (Integer i : alltimeDifference) {
            LocalDateTime startTime = processTime.plusMinutes(i);
            List<BigDecimal> data = collect.get(startTime);
            if (null == data) {
                continue;
            }
            MinAndMax minAndMax1 = dataService.getMinAndMax(data);
            BigDecimal meaningfulValues = dataService.getMeaningfulValues(minAndMax1, median);
            meaningfulValues = dataService.formulaCalculation(meaningfulValues, median);
            switch (i) {
                case 1:
                    wideData.setFuture01min(meaningfulValues);
                    break;
                case 2:
                    wideData.setFuture02min(meaningfulValues);
                    break;
                case 3:
                    wideData.setFuture03min(meaningfulValues);
                    break;
                case 4:
                    wideData.setFuture04min(meaningfulValues);
                    break;
                case 5:
                    wideData.setFuture05min(meaningfulValues);
                    break;
                case 6:
                    wideData.setFuture06min(meaningfulValues);
                    break;
                case 7:
                    wideData.setFuture07min(meaningfulValues);
                    break;
                case 8:
                    wideData.setFuture08min(meaningfulValues);
                    break;
                case 9:
                    wideData.setFuture09min(meaningfulValues);
                    break;
                case 10:
                    wideData.setFuture10min(meaningfulValues);
                    break;
                case 15:
                    wideData.setFuture15min(meaningfulValues);
                    break;
                case 20:
                    wideData.setFuture20min(meaningfulValues);
                    break;
                case 30:
                    wideData.setFuture30min(meaningfulValues);
                    break;
                case 60:
                    wideData.setFuture60min(meaningfulValues);
                    break;
                case 120:
                    wideData.setFuture120min(meaningfulValues);
                    break;
                case 240:
                    wideData.setFuture240min(meaningfulValues);
                    break;
                case -1:
                    wideData.setPast01min(meaningfulValues);
                    break;
                case -2:
                    wideData.setPast02min(meaningfulValues);
                    break;
                case -3:
                    wideData.setPast03min(meaningfulValues);
                    break;
                case -4:
                    wideData.setPast04min(meaningfulValues);
                    break;
                case -5:
                    wideData.setPast05min(meaningfulValues);
                    break;
                case -6:
                    wideData.setPast06min(meaningfulValues);
                    break;
                case -7:
                    wideData.setPast07min(meaningfulValues);
                    break;
                case -8:
                    wideData.setPast08min(meaningfulValues);
                    break;
                case -9:
                    wideData.setPast09min(meaningfulValues);
                    break;
                case -10:
                    wideData.setPast10min(meaningfulValues);
                    break;
                case -15:
                    wideData.setPast15min(meaningfulValues);
                    break;
                case -20:
                    wideData.setPast20min(meaningfulValues);
                    break;
                case -30:
                    wideData.setPast30min(meaningfulValues);
                    break;
                case -60:
                    wideData.setPast60min(meaningfulValues);
                    break;
                case -120:
                    wideData.setPast120min(meaningfulValues);
                    break;
                case -240:
                    wideData.setPast240min(meaningfulValues);
                    break;
            }
        }
        wideDataService.saveOne(wideData,caseName);
    }

    @Override
    public void processingDatas(List<BaseData> baseDataList, String caseName) {
        System.err.println("caseName" + caseName + "数据获取完成，进入数据处理阶段");
        LocalDateTime startProcesses = LocalDateTime.now();
        ddlRunner(caseName);
        HashMap<LocalDateTime, List<BigDecimal>> collect = baseDataList.stream()
                .collect(Collectors.groupingBy(
                        // 转换key，将日期时间舍弃秒信息
                        baseData -> baseData.getDate().truncatedTo(ChronoUnit.MINUTES),
                        // 初始化映射值列表
                        HashMap::new,
                        // 收集器，将每项数据的BigDecimal添加到对应的分钟桶里
                        Collectors.mapping(BaseData::getData, Collectors.toList())
                ));
        for (LocalDateTime localDateTime : collect.keySet()) {
            processingData(baseDataList,localDateTime,caseName);
        }
        Duration duration = Duration.between(startProcesses, LocalDateTime.now());
        System.err.println("当前caseName:" + caseName + "处理全部时间为" + duration.getSeconds() + "秒！");
    }

    @Override
    public void ddlRunner(String caseName) {
        Connection conn = null;
        try {
            conn = dataSource.getConnection();
            Statement statement = conn.createStatement();
            statement.execute("drop table if exists " + caseName + "_wideData;\n");
            String caseSql2 = "create table if not exists startSQL." + caseName + "_wideData\n" +
                    "(\n" +
                    "    past240min   decimal(30, 10) null,\n" +
                    "    past120min   decimal(30, 10) null,\n" +
                    "    past60min    decimal(30, 10) null,\n" +
                    "    past30min    decimal(30, 10) null,\n" +
                    "    past20min    decimal(30, 10) null,\n" +
                    "    past15min    decimal(30, 10) null,\n" +
                    "    past10min    decimal(30, 10) null,\n" +
                    "    past09min    decimal(30, 10) null,\n" +
                    "    past08min    decimal(30, 10) null,\n" +
                    "    past07min    decimal(30, 10) null,\n" +
                    "    past06min    decimal(30, 10) null,\n" +
                    "    past05min    decimal(30, 10) null,\n" +
                    "    past04min    decimal(30, 10) null,\n" +
                    "    past03min    decimal(30, 10) null,\n" +
                    "    past02min    decimal(30, 10) null,\n" +
                    "    past01min    decimal(30, 10) null,\n" +
                    "    date_time    datetime       not null,\n" +
                    "    now_data     decimal(30, 10) not null,\n" +
                    "    min_data     decimal(30, 10) not null,\n" +
                    "    max_data     decimal(30, 10) not null,\n" +
                    "    future01min  decimal(30, 10) null,\n" +
                    "    future02min  decimal(30, 10) null,\n" +
                    "    future03min  decimal(30, 10) null,\n" +
                    "    future04min  decimal(30, 10) null,\n" +
                    "    future05min  decimal(30, 10) null,\n" +
                    "    future06min  decimal(30, 10) null,\n" +
                    "    future07min  decimal(30, 10) null,\n" +
                    "    future08min  decimal(30, 10) null,\n" +
                    "    future09min  decimal(30, 10) null,\n" +
                    "    future10min  decimal(30, 10) null,\n" +
                    "    future15min  decimal(30, 10) null,\n" +
                    "    future20min  decimal(30, 10) null,\n" +
                    "    future30min  decimal(30, 10) null,\n" +
                    "    future60min  decimal(30, 10) null,\n" +
                    "    future120min decimal(30, 10) null,\n" +
                    "    future240min decimal(30, 10) null\n" +
                    ") ENGINE = MEMORY;";
            statement.execute(caseSql2);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}
